package com.yst.web.utils;

import java.util.concurrent.*;

public final class ThreadPoolBuilder {

    public static final int DEFAULT_QUEUE_CAPACITY = 1024;
    private int corePoolSize;
    private int maxPoolSize = Integer.MAX_VALUE;
    private long keepAliveTime;
    private BlockingQueue<Runnable> workQueue;
    private ThreadFactory threadFactory;
    private RejectedExecutionHandler handler;
    private Boolean allowCoreThreadTimeOut;

    public ThreadPoolBuilder() {
        this.keepAliveTime = TimeUnit.SECONDS.toNanos(60L);
    }

    public ThreadPoolBuilder setCorePoolSize(int corePoolSize) {
        this.corePoolSize = corePoolSize;
        return this;
    }

    public ThreadPoolBuilder setMaxPoolSize(int maxPoolSize) {
        this.maxPoolSize = maxPoolSize;
        return this;
    }

    public ThreadPoolBuilder setKeepAliveTime(long keepAliveTime, TimeUnit unit) {
        return this.setKeepAliveTime(unit.toNanos(keepAliveTime));
    }

    public ThreadPoolBuilder setKeepAliveTime(long keepAliveTime) {
        this.keepAliveTime = keepAliveTime;
        return this;
    }

    public ThreadPoolBuilder setWorkQueue(BlockingQueue<Runnable> workQueue) {
        this.workQueue = workQueue;
        return this;
    }

    public ThreadPoolBuilder useArrayBlockingQueue(int capacity) {
        return this.setWorkQueue(new ArrayBlockingQueue<>(capacity));
    }

    public ThreadPoolBuilder useSynchronousQueue() {
        return this.useSynchronousQueue(false);
    }

    public ThreadPoolBuilder useSynchronousQueue(boolean fair) {
        return this.setWorkQueue(new SynchronousQueue<>(fair));
    }

    public ThreadPoolBuilder setThreadFactory(ThreadFactory threadFactory) {
        this.threadFactory = threadFactory;
        return this;
    }

    public ThreadPoolBuilder setHandler(RejectedExecutionHandler handler) {
        this.handler = handler;
        return this;
    }

    public ThreadPoolBuilder setAllowCoreThreadTimeOut(boolean allowCoreThreadTimeOut) {
        this.allowCoreThreadTimeOut = allowCoreThreadTimeOut;
        return this;
    }

    public ThreadPoolExecutor build() {
        return build(this);
    }

    private static ThreadPoolExecutor build(ThreadPoolBuilder builder) {
        int corePoolSize = builder.corePoolSize;
        int maxPoolSize = builder.maxPoolSize;
        long keepAliveTime = builder.keepAliveTime;
        Object workQueue;
        if (null != builder.workQueue) {
            workQueue = builder.workQueue;
        } else {
            workQueue = corePoolSize <= 0 ? new SynchronousQueue<>() : new LinkedBlockingQueue<>(1024);
        }

        ThreadFactory threadFactory = null != builder.threadFactory ? builder.threadFactory : Executors.defaultThreadFactory();
        RejectedExecutionHandler handler = builder.handler;
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(corePoolSize, maxPoolSize, keepAliveTime, TimeUnit.NANOSECONDS, (BlockingQueue)workQueue, threadFactory, handler);
        if (null != builder.allowCoreThreadTimeOut) {
            threadPoolExecutor.allowCoreThreadTimeOut(builder.allowCoreThreadTimeOut);
        }

        return threadPoolExecutor;
    }
}
